博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
javaWeb中的文件上传下载
阅读量:5091 次
发布时间:2019-06-13

本文共 24680 字,大约阅读时间需要 82 分钟。

在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现。

  对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上传文件的输入流然后再解析里面的请求参数是比较麻烦,所以一般选择采用apache的开源工具common-fileupload这个文件上传组件。这个common-fileupload上传组件的jar包可以去apache官网上面下载,也可以在struts的lib文件夹下面找到,struts上传的功能就是基于这个实现的。common-fileupload是依赖于common-io这个包的,所以还需要下载这个包,也可以直接去maven库中搜索这个包。如果使用servlet3.0的话就不需要下载包了,直接支持文件上传。

apache官网也有servlet部分的代码演示和讲解,地址:

环境目录:

index.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"    pageEncoding="utf-8"%>
Insert title here上传
下载

 

upload.jsp代码

<%@ page language="java" pageEncoding="UTF-8"%>      Servlet3.0实现文件上传              
上传单个文件         //${pageContext.request.contextPath}保证部署后路径正确
上传文件:

上传多个文件
上传文件:
上传文件:

 

开发处理文件上传的Servlet

  1、使用注解@MultipartConfig将一个Servlet标识为支持文件上传。

  2、Servlet3.0将multipart/form-data的POST请求封装成Part,通过Part对上传的文件进行操作

 

package servlet;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.List;import javax.servlet.ServletException;import javax.servlet.annotation.MultipartConfig;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.fileupload.FileItem;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload;//使用@WebServlet配置UploadServlet的访问路径@WebServlet(name="UploadServlet",urlPatterns="/UploadServlet")//使用注解@MultipartConfig将一个Servlet标识为支持文件上传@MultipartConfig//标识Servlet支持文件上传public class UploadServlet extends HttpServlet {    /**	 * 	 */	private static final long serialVersionUID = 1L;	public void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {                //得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全                String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");                File file = new File(savePath);                //判断上传文件的保存目录是否存在                if (!file.exists() && !file.isDirectory()) {                    System.out.println(savePath+"目录不存在,需要创建");                    //创建目录                    file.mkdir();                }                //消息提示                String message = "";                try{                    //使用Apache文件上传组件处理文件上传步骤:                    //1、创建一个DiskFileItemFactory工厂                    DiskFileItemFactory factory = new DiskFileItemFactory();                    //2、创建一个文件上传解析器                    ServletFileUpload upload = new ServletFileUpload(factory);                     //解决上传文件名的中文乱码                    upload.setHeaderEncoding("UTF-8");                     //3、判断提交上来的数据是否是上传表单的数据                    if(!ServletFileUpload.isMultipartContent(request)){                        //按照传统方式获取数据                        return;                    }                    //4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List
集合,每一个FileItem对应一个Form表单的输入项 List
list = upload.parseRequest(request); for(FileItem item : list){ //如果fileitem中封装的是普通输入项的数据 if(item.isFormField()){ String name = item.getFieldName(); //解决普通输入项的数据的中文乱码问题 String value = item.getString("UTF-8"); //value = new String(value.getBytes("iso8859-1"),"UTF-8"); System.out.println(name + "=" + value); }else{//如果fileitem中封装的是上传文件 //得到上传的文件名称, String filename = item.getName(); System.out.println(filename); if(filename==null || filename.trim().equals("")){ continue; } //注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如: c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt //处理获取到的上传文件的文件名的路径部分,只保留文件名部分 filename = filename.substring(filename.lastIndexOf("\\")+1); //获取item中的上传文件的输入流 InputStream in = item.getInputStream(); //创建一个文件输出流 FileOutputStream out = new FileOutputStream(savePath + "\\" + filename); //创建一个缓冲区 byte buffer[] = new byte[1024]; //判断输入流中的数据是否已经读完的标识 int len = 0; //循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据 while((len=in.read(buffer))>0){ //使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中 out.write(buffer, 0, len); } //关闭输入流 in.close(); //关闭输出流 out.close(); //删除处理文件上传时生成的临时文件 item.delete(); message = "文件上传成功!"; } } }catch (Exception e) { message= "文件上传失败!"; e.printStackTrace(); } request.setAttribute("message",message); request.getRequestDispatcher("/message.jsp").forward(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }}

 上传成功后meaasge.jsp

<%@ page language="java" pageEncoding="UTF-8"%>      消息提示              ${message}  

 web.xml配置

Spring MVC Application
index.jsp

 

文件上传的细节

  上述的代码虽然可以成功将文件上传到服务器上面的指定目录当中,但是文件上传功能有许多需要注意的小细节问题,以下列出的几点需要特别注意的

  1、为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。

  2、为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。

  3、为防止一个目录下面出现太多文件,要使用hash算法打散存储。

  4、要限制上传文件的最大值。

  5、要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。

  针对上述提出的5点细节问题,我们来改进一下UploadHandleServlet,改进后的代码如下:

package servlet;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.List;import java.util.UUID;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.fileupload.FileItem;import org.apache.commons.fileupload.FileUploadBase;import org.apache.commons.fileupload.ProgressListener;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload;//使用@WebServlet配置UploadServlet的访问路径 @WebServlet(name="UploadServlet",urlPatterns="/UploadServlet") //使用注解@MultipartConfig将一个Servlet标识为支持文件上传 @MultipartConfig//标识Servlet支持文件上传public class UploadServlet extends HttpServlet {    public void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {                //得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全                String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");                //上传时生成的临时文件保存目录                String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp");                File tmpFile = new File(tempPath);                if (!tmpFile.exists()) {                    //创建临时目录                    tmpFile.mkdir();                }                                //消息提示                String message = "";                try{                    //使用Apache文件上传组件处理文件上传步骤:                    //1、创建一个DiskFileItemFactory工厂                    DiskFileItemFactory factory = new DiskFileItemFactory();                    //设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,就会生成一个临时文件存放到指定的临时目录当中。                    factory.setSizeThreshold(1024*100);//设置缓冲区的大小为100KB,如果不指定,那么缓冲区的大小默认是10KB                    //设置上传时生成的临时文件的保存目录                    factory.setRepository(tmpFile);                    //2、创建一个文件上传解析器                    ServletFileUpload upload = new ServletFileUpload(factory);                    //监听文件上传进度                    upload.setProgressListener(new ProgressListener(){                        public void update(long pBytesRead, long pContentLength, int arg2) {                            System.out.println("文件大小为:" + pContentLength + ",当前已处理:" + pBytesRead);                            /**                             * 文件大小为:14608,当前已处理:4096                                文件大小为:14608,当前已处理:7367                                文件大小为:14608,当前已处理:11419                                文件大小为:14608,当前已处理:14608                             */                        }                    });                     //解决上传文件名的中文乱码                    upload.setHeaderEncoding("UTF-8");                     //3、判断提交上来的数据是否是上传表单的数据                    if(!ServletFileUpload.isMultipartContent(request)){                        //按照传统方式获取数据                        return;                    }                                        //设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB                    upload.setFileSizeMax(1024*1024);                    //设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB                    upload.setSizeMax(1024*1024*10);                    //4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List
集合,每一个FileItem对应一个Form表单的输入项 List
list = upload.parseRequest(request); for(FileItem item : list){ //如果fileitem中封装的是普通输入项的数据 if(item.isFormField()){ String name = item.getFieldName(); //解决普通输入项的数据的中文乱码问题 String value = item.getString("UTF-8"); //value = new String(value.getBytes("iso8859-1"),"UTF-8"); System.out.println(name + "=" + value); }else{//如果fileitem中封装的是上传文件 //得到上传的文件名称, String filename = item.getName(); System.out.println(filename); if(filename==null || filename.trim().equals("")){ continue; } //注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如: c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt //处理获取到的上传文件的文件名的路径部分,只保留文件名部分 filename = filename.substring(filename.lastIndexOf("\\")+1); //得到上传文件的扩展名 String fileExtName = filename.substring(filename.lastIndexOf(".")+1); //如果需要限制上传的文件类型,那么可以通过文件的扩展名来判断上传的文件类型是否合法 System.out.println("上传的文件的扩展名是:"+fileExtName); //获取item中的上传文件的输入流 InputStream in = item.getInputStream(); //得到文件保存的名称 String saveFilename = makeFileName(filename); //得到文件的保存目录 String realSavePath = makePath(saveFilename, savePath); //创建一个文件输出流 FileOutputStream out = new FileOutputStream(realSavePath + "\\" + saveFilename); //创建一个缓冲区 byte buffer[] = new byte[1024]; //判断输入流中的数据是否已经读完的标识 int len = 0; //循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据 while((len=in.read(buffer))>0){ //使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中 out.write(buffer, 0, len); } //关闭输入流 in.close(); //关闭输出流 out.close(); //删除处理文件上传时生成的临时文件 //item.delete(); message = "文件上传成功!"; } } }catch (FileUploadBase.FileSizeLimitExceededException e) { e.printStackTrace(); request.setAttribute("message", "单个文件超出最大值!!!"); request.getRequestDispatcher("/message.jsp").forward(request, response); return; }catch (FileUploadBase.SizeLimitExceededException e) { e.printStackTrace(); request.setAttribute("message", "上传文件的总的大小超出限制的最大值!!!"); request.getRequestDispatcher("/message.jsp").forward(request, response); return; }catch (Exception e) { message= "文件上传失败!"; e.printStackTrace(); } request.setAttribute("message",message); request.getRequestDispatcher("/message.jsp").forward(request, response); } /** * @Method: makeFileName * @Description: 生成上传文件的文件名,文件名以:uuid+"_"+文件的原始名称 * @param filename 文件的原始名称 * @return uuid+"_"+文件的原始名称 */ private String makeFileName(String filename){ //2.jpg //为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名 return UUID.randomUUID().toString() + "_" + filename; } /** * 为防止一个目录下面出现太多文件,要使用hash算法打散存储 * @Method: makePath * @Description: * * @param filename 文件名,要根据文件名生成存储目录 * @param savePath 文件存储路径 * @return 新的存储目录 */ private String makePath(String filename,String savePath){ //得到文件名的hashCode的值,得到的就是filename这个字符串对象在内存中的地址 int hashcode = filename.hashCode(); int dir1 = hashcode&0xf; //0--15 int dir2 = (hashcode&0xf0)>>4; //0-15 //构造新的保存目录 String dir = savePath + "\\" + dir1 + "\\" + dir2; //upload\2\3 upload\3\5 //File既可以代表文件也可以代表目录 File file = new File(dir); //如果目录不存在 if(!file.exists()){ //创建目录 file.mkdirs(); } return dir; } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }}

 

使用Servlet3.0上传文件

package servlet;import java.io.File;import java.io.IOException;import java.io.PrintWriter;import java.util.Collection;import javax.servlet.ServletException;import javax.servlet.annotation.MultipartConfig;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.Part;//使用@WebServlet配置UploadServlet的访问路径@WebServlet(name = "FileUploadServlet", urlPatterns = "/FileUploadServlet")// 使用注解@MultipartConfig将一个Servlet标识为支持文件上传@MultipartConfig // 标识Servlet支持文件上传public class FileUploadServlet extends HttpServlet {	public void doGet(HttpServletRequest request, HttpServletResponse response)			throws ServletException, IOException {		request.setCharacterEncoding("utf-8");		response.setCharacterEncoding("utf-8");		response.setContentType("text/html;charset=utf-8");		// 存储路径		String savePath = "D:\\";		// 获取上传的文件集合		Collection
parts = request.getParts(); // 上传单个文件 if (parts.size() == 1) { // Servlet3.0将multipart/form-data的POST请求封装成Part,通过Part对上传的文件进行操作。 // Part part = parts[0];//从上传的文件集合中获取Part对象 Part part = request.getPart("file");// 通过表单file控件(
)的名字直接获取Part对象 // Servlet3没有提供直接获取文件名的方法,需要从请求头中解析出来 // 获取请求头,请求头的格式:form-data; name="file"; filename="snmp4j--api.zip" String header = part.getHeader("content-disposition"); // 获取文件名 String fileName = getFileName(header); // 把文件写到指定路径 part.write(savePath + File.separator + fileName); } else { // 一次性上传多个文件 for (Part part : parts) {// 循环处理上传的文件 // 获取请求头,请求头的格式:form-data; name="file"; // filename="snmp4j--api.zip" String header = part.getHeader("content-disposition"); // 获取文件名 String fileName = getFileName(header); // 把文件写到指定路径 part.write(savePath + File.separator + fileName); } } PrintWriter out = response.getWriter(); out.println("上传成功"); out.flush(); out.close(); } /** * 根据请求头解析出文件名 请求头的格式:火狐和google浏览器下:form-data; name="file"; * filename="snmp4j--api.zip" IE浏览器下:form-data; name="file"; * filename="E:\snmp4j--api.zip" * * @param header * 请求头 * @return 文件名 */ public String getFileName(String header) { /** * String[] tempArr1 = * header.split(";");代码执行完之后,在不同的浏览器下,tempArr1数组里面的内容稍有区别 * 火狐或者google浏览器下:tempArr1={form-data,name="file",filename= * "snmp4j--api.zip"} * IE浏览器下:tempArr1={form-data,name="file",filename="E:\snmp4j--api.zip"} */ String[] tempArr1 = header.split(";"); /** * 火狐或者google浏览器下:tempArr2={filename,"snmp4j--api.zip"} * IE浏览器下:tempArr2={filename,"E:\snmp4j--api.zip"} */ String[] tempArr2 = tempArr1[2].split("="); // 获取文件名,兼容各种浏览器的写法 String fileName = tempArr2[1] .substring(tempArr2[1].lastIndexOf("\\") + 1) .replaceAll("\"", ""); return fileName; } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); }}

点击下载要从web-inf下找到目录文件并且列出到download.jsp中

ListFileServlet

package servlet;import java.io.File;import java.io.IOException;import java.util.HashMap;import java.util.Map;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/*** @ClassName: ListFileServlet* @Description: 列出Web系统中所有下载文件* @date: 2015-1-4 下午9:54:40**/ @WebServlet(name="ListFileServlet",urlPatterns="/download")public class ListFileServlet  extends HttpServlet{    /**	 * 	 */	private static final long serialVersionUID = 1L;	public void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        //获取上传文件的目录        String uploadFilePath = this.getServletContext().getRealPath("/WEB-INF/upload");        //存储要下载的文件名        Map
fileNameMap = new HashMap
(); //递归遍历filepath目录下的所有文件和目录,将文件的文件名存储到map集合中 listfile(new File(uploadFilePath),fileNameMap);//File既可以代表一个文件也可以代表一个目录 //将Map集合发送到listfile.jsp页面进行显示 request.setAttribute("fileNameMap", fileNameMap); request.getRequestDispatcher("/download.jsp").forward(request, response); } /** * @Method: listfile * @Description: 递归遍历指定目录下的所有文件 * @param file 即代表一个文件,也代表一个文件目录 * @param map 存储文件名的Map集合 */ public void listfile(File file,Map
map){ //如果file代表的不是一个文件,而是一个目录 if(!file.isFile()){ //列出该目录下的所有文件和目录 File files[] = file.listFiles(); //遍历files[]数组 for(File f : files){ //递归 listfile(f,map); } }else{ /** * 处理文件名,上传后的文件是以uuid_文件名的形式去重新命名的,去除文件名的uuid_部分 file.getName().indexOf("_")检索字符串中第一次出现"_"字符的位置,如果文件名类似于:9349249849-88343-8344_阿_凡_达.avi 那么file.getName().substring(file.getName().indexOf("_")+1)处理之后就可以得到阿_凡_达.avi部分 */ String realName = file.getName().substring(file.getName().indexOf("_")+1); //file.getName()得到的是文件的原始名称,这个名称是唯一的,因此可以作为key,realName是处理过后的名称,有可能会重复 map.put(file.getName(), realName); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); }}

 download.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>      下载文件显示页面            
${me.value}
下载

 点击下载处理Servlet

package servlet;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.OutputStream;import java.net.URLEncoder;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;@WebServlet(name = "DownLoadServlet", urlPatterns = "/DownLoadServlet")public class DownLoadServlet extends HttpServlet {	public void doGet(HttpServletRequest request, HttpServletResponse response)			throws ServletException, IOException {		// 得到要下载的文件名		String fileName = request.getParameter("filename"); // 23239283-92489-阿凡达.avi		fileName = new String(fileName.getBytes("iso8859-1"), "UTF-8");		// 上传的文件都是保存在/WEB-INF/upload目录下的子目录当中		String fileSaveRootPath = this.getServletContext()				.getRealPath("/WEB-INF/upload");		// 通过文件名找出文件的所在目录		String path = findFileSavePathByFileName(fileName, fileSaveRootPath);		// 得到要下载的文件		File file = new File(path + "\\" + fileName);		// 如果文件不存在		if (!file.exists()) {			request.setAttribute("message", "您要下载的资源已被删除!!");			request.getRequestDispatcher("/message.jsp").forward(request,					response);			return;		}		// 处理文件名		String realname = fileName.substring(fileName.indexOf("_") + 1);		// 设置响应头,控制浏览器下载该文件		response.setHeader("content-disposition",				"attachment;filename=" + URLEncoder.encode(realname, "UTF-8"));		// 读取要下载的文件,保存到文件输入流		FileInputStream in = new FileInputStream(path + "\\" + fileName);		// 创建输出流		OutputStream out = response.getOutputStream();		// 创建缓冲区		byte buffer[] = new byte[1024];		int len = 0;		// 循环将输入流中的内容读取到缓冲区当中		while ((len = in.read(buffer)) > 0) {			// 输出缓冲区的内容到浏览器,实现文件下载			out.write(buffer, 0, len);		}		// 关闭文件输入流		in.close();		// 关闭输出流		out.close();	}	/**	 * @Method: findFileSavePathByFileName	 * @Description: 通过文件名和存储上传文件根目录找出要下载的文件的所在路径	 * @param filename	 *            要下载的文件名	 * @param saveRootPath	 *            上传文件保存的根目录,也就是/WEB-INF/upload目录	 * @return 要下载的文件的存储目录	 */	public String findFileSavePathByFileName(String filename,			String saveRootPath) {		int hashcode = filename.hashCode();		int dir1 = hashcode & 0xf; // 0--15		int dir2 = (hashcode & 0xf0) >> 4; // 0-15		String dir = saveRootPath + "\\" + dir1 + "\\" + dir2; // upload\2\3								      // upload\3\5		File file = new File(dir);		if (!file.exists()) {			// 创建目录			file.mkdirs();		}		return dir;	}	public void doPost(HttpServletRequest request, HttpServletResponse response)			throws ServletException, IOException {		doGet(request, response);	}}

 

使用JSPSmartUpload文件上传(未进行优化,使用场景是提交除了上传文件,还有其他值)

package servlet;import java.io.IOException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import service.GoodsService;import service.impl.GoodsServiceImpl;import com.jspsmart.upload.SmartUpload;import entity.Goods;/** * 增加商品 2015-3-6 */@WebServlet(urlPatterns = "/addGoods")public class GoodsAddGoodsServlet extends HttpServlet {	private static final long serialVersionUID = 1L;	GoodsService service = new GoodsServiceImpl();	Goods goods = new Goods();	public GoodsAddGoodsServlet() {		super();	}	@Override	public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {		// 初始化下载对象		SmartUpload su = new SmartUpload();		try {			// 初始化上传对象			su.initialize(getServletConfig(), request, response);			// 设置单文件最大容量			su.setMaxFileSize(10 * 1024 * 1024);			// 设置所有文件最大容量			su.setTotalMaxFileSize(100 * 1024 * 1024);			// 设置上传文件类型			su.setAllowedFilesList("jpg,bmp,gif,png");			// 设置禁止上传的文件类型			su.setDeniedFilesList("jsp,js,html,css,rar,txt");			// 上传文件			su.upload();			// 获取单个上传文件			com.jspsmart.upload.File tempFile = null;			//多文件上传			/*for( int i=0; i

 注意:上面这种方式由于放在临时目录中,每次重启tomcat上传的文件会自动消失,可以在上传至服务器目录时再上传备份一个至硬盘中,如String savePath = "D:\\";

Appache Commons Upload文件上传

 

转载于:https://www.cnblogs.com/JAYIT/p/5028524.html

你可能感兴趣的文章
WebDriverExtensionsByC#
查看>>
我眼中的技术地图
查看>>
lc 145. Binary Tree Postorder Traversal
查看>>
sublime 配置java运行环境
查看>>
在centos上开关tomcat
查看>>
重启rabbitmq服务
查看>>
正则表达式(进阶篇)
查看>>
无人值守安装linux系统
查看>>
【传道】中国首部淘宝卖家演讲公开课:农业本该如此
查看>>
jQuery应用 代码片段
查看>>
MVC+Servlet+mysql+jsp读取数据库信息
查看>>
黑马程序员——2 注释
查看>>
用OGRE1.74搭建游戏框架(三)--加入人物控制和场景
查看>>
转化课-计算机基础及上网过程
查看>>
android dialog使用自定义布局 设置窗体大小位置
查看>>
ionic2+ 基础
查看>>
互联网模式下我们更加应该“专注”
查看>>
myeclipse集成jdk、tomcat8、maven、svn
查看>>
查询消除重复行
查看>>
Win 10 文件浏览器无法打开
查看>>